---
title: Assemblers
---
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

Assemblers are used to translate your DTO into the underlying database type and back.

## When to use Assemblers

In most cases an Assembler will not be required because your Entity and DTO will be the same shape.

The only time you need to define an assembler is when the DTO and Entity are different. The most common scenarios are

* Additional computed fields and you do not want to include the business logic in your DTO definition.
* Different field names because of poorly named columns in the database or to make a DB change passive to the end user.
* You need to transform the create or update DTO before being passed to your persistence QueryService

## Why?

Separation of concerns.

### Resolvers
Your resolvers only concern is dealing with graphql and translating the request (a DTO) into something the service cares about.

The resolver should not care about how it is persisted. The underlying Entity **could** have additional fields that you do not want to expose in your API, or it may be persisted into multiple stores.

By separating the resolver from the persistence layer you can evolve your API separate from your database model.

### Services

The services concern are operating on a DTO, preventing the leaking of persistence details to the API.

 In `nestjs-query` services can be composed. In the case of assemblers information is translated using the assembler and delegated to an underlying service.

 This alleviates any awkwardness around passing in a DTO and receiving a different object type back. Instead, your service can use an assembler to alleviate these concerns.

### Assemblers

The assembler provides a single, testable, place to provide a translation between the DTO and entity, and vice versa.

### Why not use the assembler in the resolver?

The resolvers concern is translating graphql requests into the specified DTO.

The services concern is accepting and returning a DTO based contract. Then using an assembler to translate between the DTO and underlying entities.

If you follow this pattern you **could** use the same service with other transports (rest, microservices, etc) as long as the request can be translated into a DTO.

## ClassTransformerAssembler

In most cases the [class-transformer](https://github.com/typestack/class-transformer) package will properly map back and forth. Because of this there is a `ClassTransformerAssembler` that leverages the `plainToClass` method.

**NOTE** The `ClassTransformerAssembler` is the default implementation if an `Assembler` is not manually defined.

If you find yourself in a scenario where you need to compute values and you dont want to add the business logic to your DTO you can extend the `ClassTransformerAssembler`.

Lets take a simple example, where we have `TodoItemDTO` and we want to compute the `age`.

```ts title="todo-item.assembler.ts"
import { Assembler, ClassTransformerAssembler } from '@nestjs-query/core';
import { TodoItemDTO } from './dto/todo-item.dto';
import { TodoItemEntity } from './todo-item.entity';

// `@Assembler` decorator will register the assembler with `nestjs-query` and
// the QueryService service will be able to auto discover it.
@Assembler(TodoItemDTO, TodoItemEntity)
export class TodoItemAssembler extends ClassTransformerAssembler<TodoItemDTO, TodoItemEntity> {
  convertToDTO(entity: TodoItemEntity): TodoItemDTO {
    const dto = super.convertToDTO(entity);
    // compute the age
    dto.age = Date.now() - entity.created.getMilliseconds();
    return dto;
  }
}
```

While this example is fairly trivial, the same pattern should apply for more complex scenarios.

## AbstractAssembler

To create your own `Assembler` extend the `AbstractAssembler`.

Lets assume we have the following `UserDTO`.

```ts title="user.dto.ts"
import { FilterableField } from '@nestjs-query/query-graphql';
import { ObjectType } from '@nestjs/graphql';

@ObjectType('User')
class UserDTO {
  @FilterableField()
  firstName!: string;

  @FilterableField()
  lastName!: string;

  @FilterableField()
  emailAddress!: string;
}

```

But you inherited a DB schema that has names that are not as user friendly.

<Tabs
  defaultValue="typeorm"
  groupId="orm"
  values={[
    { label: 'TypeOrm', value: 'typeorm', },
    { label: 'Sequelize', value: 'sequelize', },
    { label: 'Mongoose', value: 'mongoose', },
  ]
}>
<TabItem value="typeorm">

```ts title="user.entity.ts"
import {Entity, Column} from 'typeorm'

@Entity()
class UserEntity {
  @Column()
  first!: string;

  @Column()
  last!: string;

  @Column()
  email!: string;
}
```

</TabItem>
<TabItem value="sequelize">

```ts title="user.entity.ts"
import { Table, Column, Model } from 'sequelize-typescript';

@Table
export class UserEntity extends Model<UserEntity, Partial<UserEntity>> {
   @Column
   first!: string;

   @Column
   last!: string;

   @Column
   email!: string;
}

```

</TabItem>
<TabItem value="mongoose">

```ts title="user.entity.ts"
import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';
import { Document } from 'mongoose';

@Schema()
export class UserEntity extends Document {
  @Prop({ required: true })
  first!: string;

  @Prop({ required: true })
  last!: string;

  @Prop({ required: true })
  email!: string;
}

export const UserEntityEntitySchema = SchemaFactory.createForClass(UserEntity);

```

</TabItem>
</Tabs>

To properly translate the `UserDTO` into the `UserEntity` and back you can extend an `Assembler` that the `QueryService` will use.

```ts title="user.assembler.ts"
import {
  AbstractAssembler,
  Assembler,
  Query,
  transformQuery,
  transformAggregateQuery,
  transformAggregateResponse
} from '@nestjs-query/core';
import { UserDTO } from './dto/user.dto';
import { UserEntity } from './user.entity';

// `@Assembler` decorator will register the assembler with `nestjs-query` and
// the QueryService service will be able to auto discover it.
@Assembler(UserDTO, UserEntity)
export class UserAssembler extends AbstractAssembler<UserDTO, UserEntity> {
  convertQuery(query: Query<UserDTO>): Query<UserEntity> {
    return transformQuery(query, {
      firstName: 'first',
      lastName: 'last',
      emailAddress: 'email',
    });
  }

  convertToDTO(entity: UserEntity): UserDTO {
    const dto = new UserDTO();
    dto.firstName = entity.first;
    dto.lastName = entity.last;
    return dto;
  }

  convertToEntity(dto: UserDTO): UserEntity {
    const entity = new UserEntity();
    entity.first = dto.firstName;
    entity.last = dto.lastName;
    return entity;
  }

  convertAggregateQuery(aggregate: AggregateQuery<TestDTO>): AggregateQuery<TestEntity> {
     return transformAggregateQuery(aggregate, {
       firstName: 'first',
       lastName: 'last',
       emailAddress: 'email',
    });
  }

  convertAggregateResponse(aggregate: AggregateResponse<TestEntity>): AggregateResponse<TestDTO> {
    return transformAggregateResponse(aggregate, {
      first: 'firstName',
      last: 'lastName',
      email: 'emailAddress'
    });
  }

  convertToCreateEntity({firstName, lastName}: DeepPartial<TestDTO>): DeepPartial<TestEntity> {
    return {
      first: firstName,
      last: lastName,
    };
  }

  convertToUpdateEntity({firstName, lastName}: DeepPartial<TestDTO>): DeepPartial<TestEntity> {
    return {
      first: firstName,
      last: lastName,
    };
  }
}

```

The first thing to look at is the `@Assembler` decorator. It will register the assembler with `nestjs-query` so `QueryServices` can look it up later.

```ts
@Assembler(UserDTO, UserEntity)
```

### Converting the Query

Next the `convertQuery` method.

```ts
convertQuery(query: Query<UserDTO>): Query<UserEntity> {
  return transformQuery(query, {
    firstName: 'first',
    lastName: 'last',
    emailAddress: 'email',
  });
}
```

This method leverages the `transformQuery` function from `@nestjs-query/core`. This method will remap all fields specified in the field map to correct field name.

In this example

```ts
{
  filter: {
    firstName: { eq: 'Bob' },
    lastName: { eq: 'Yukon' },
    emailAddress: { eq: 'bob@yukon.com' }
  }
}
```

Would be transformed into.

```ts
{
  filter: {
    first: { eq: 'Bob' },
    last: { eq: 'Yukon' },
    email: { eq: 'bob@yukon.com' }
  }
}
```

### Converting the DTO

The next piece is the `convertToDTO`, which will convert the entity into a the correct DTO.

```ts
convertToDTO(entity: UserEntity): UserDTO {
  const dto = new UserDTO();
  dto.firstName = entity.first;
  dto.lastName = entity.last;
  return dto;
}
```

### Converting the Entity

The next piece is the `convertToEntity`, which will convert the DTO into a the correct entity.

```ts
convertToEntity(dto: UserDTO): UserEntity {
  const entity = new UserEntity();
  entity.first = dto.firstName;
  entity.last = dto.lastName;
  return entity;
}
```

### Converting Aggregate Query

The `convertAggregateQuery` is used to convert an `AggregateQuery`. This examples uses the `transformAggregateQuery` helper to map aggregate query fields.

```ts
convertAggregateQuery(aggregate: AggregateQuery<TestDTO>): AggregateQuery<TestEntity> {
   return transformAggregateQuery(aggregate, {
     firstName: 'first',
     lastName: 'last',
     emailAddress: 'email',
  });
}
```

### Converting Aggregate Response

The `convertAggregateResponse` is used to convert an `AggregateResponse`. This examples uses the `transformAggregateResponse` helper to map aggregate response fields.

```ts
convertAggregateResponse(aggregate: AggregateResponse<TestEntity>): AggregateResponse<TestDTO> {
  return transformAggregateResponse(aggregate, {
    first: 'firstName',
    last: 'lastName',
    email: 'emailAddress'
  });
}
```

### Converting Create DTO

The `convertToCreateEntity` is used to convert an incoming create DTO to the appropriate create entity, in this case
partial.

```ts
convertToCreateEntity({firstName, lastName}: DeepPartial<TestDTO>): DeepPartial<TestEntity> {
  return {
    first: firstName,
    last: lastName,
  };
}
```

### Converting Update DTO

The `convertToUpdateEntity` is used to convert an incoming update DTO to the appropriate update entity, in this case a
partial.

```ts
convertToUpdateEntity({firstName, lastName}: DeepPartial<TestDTO>): DeepPartial<TestEntity> {
  return {
    first: firstName,
    last: lastName,
  };
}
```

This is a pretty basic example but the same pattern should apply to more complex scenarios.

## AssemblerQueryService

An `AssemblerQueryService` is a special type of `QueryService` that uses the Assembler to translate between the DTO and Entity.

The easiest way to create an `AssemblerQueryService` is to use the `@InjectAssemblerQueryService` decorator.

Before using the decorator you need to register your Assembler with `nestjs-query`

### Module

```ts title="user.module.ts" {10}
import { NestjsQueryGraphQLModule } from '@nestjs-query/query-graphql';
import { Module } from '@nestjs/common';
import { UserDTO } from './user.dto';

@Module({
  providers: [TodoItemResolver],
  imports: [
    NestjsQueryGraphQLModule.forFeature({
      imports: [ /* set up your entity with a nestjs-query persitence package */],
      assemblers: [UserAssembler],
      resolvers: [ ],
    }),
  ],
})
export class UserModule {}

```

### Auto Generated Resolver

If you want your assembler to be used by the auto-generated resolver you can specify the `AssemblerClass` option.

```ts title="user.module.ts" {10,14}
import { NestjsQueryGraphQLModule } from '@nestjs-query/query-graphql';
import { Module } from '@nestjs/common';
import { UserDTO } from './user.dto';

@Module({
  providers: [TodoItemResolver],
  imports: [
    NestjsQueryGraphQLModule.forFeature({
      imports: [ /* set up your entity with a nestjs-query persitence package */],
      assemblers: [UserAssembler],
      resolvers: [
        {
          DTOClass: UserDTO,
          AssemblerClass: UserAssembler
        }
      ],
    }),
  ],
})
export class UserModule {}

```


### Manual Resolver

If you are manually defining you resolver or want to use the `AssemblerQueryService` in another service use the `@InjectAssemblerQueryService` decorator.

```ts title="user.resolver.ts" {8}
import { CRUDResolver } from '@nestjs-query/query-graphql';
import { Resolver } from '@nestjs/graphql';
import { UserDTO } from './user.dto';
import { UserAssembler } from './user.assembler'

@Resolver(() => UserDTO)
export class UserResolver extends CRUDResolver(UserDTO) {
  constructor(@InjectAssemblerQueryService(UserAssembler) readonly service: QueryService<UserDTO>) {
    super(service);
  }
}
```

Notice `QueryService<UserDTO>`.
